package cn.bluedot.framework.core;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.bluedot.framework.annotations.Autowired;
import cn.bluedot.framework.annotations.Service;

public class BeanFactory {
	
    private static Map<Class<?>,Object> classToBean = new ConcurrentHashMap<>(); //存储键值映射

    /**
     * 获取Bean
     * @param cls
     * @return
     */
    public static Object getBean(Class<?> cls){
        return classToBean.get(cls);
    }

    /**
     * 初始化BeanFactory
     * @param classList
     */
    public static void initBean(List<Class<?>> classList) throws Exception {
        List<Class<?>> toCreate = new ArrayList<>(classList);
        while(toCreate.size() != 0) {
            int remainSize = toCreate.size(); //存储当前容器的大小
            for (int i = 0; i< toCreate.size(); i++) {
                if(finishCreate(toCreate.get(i))){ //如果已经完成了创建，则从容器中删除
                    toCreate.remove(i);
                }
            }

            if(toCreate.size() == remainSize){ //陷入死循环，抛出异常
                throw new Exception("An exception occurred while initializing the BeanFactory!");
            }

        }
    }

    /**
     * 创建Bean
     * @param cls
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private static boolean finishCreate(Class<?> cls) throws IllegalAccessException, InstantiationException {

        if(!cls.isAnnotationPresent(Service.class)){
            return true;
        }

        Object bean = cls.newInstance();  //创建Bean对象
        
        for (Field filed :cls.getDeclaredFields()){ //遍历bean的依赖，判断是否被Autowired注解
            
        	if(filed.isAnnotationPresent(Autowired.class)){ //如果被注解了
                Class<?> filedType = filed.getType();  //拿到属性的类型
                Object reliantBean =  BeanFactory.getBean(filedType);
                if(reliantBean == null){ //如果未被创建直接返回false
                    return false;
                }
                //注入到bean中
                filed.setAccessible(true); //修改可见性
                filed.set(bean, reliantBean);
            }

        }
        classToBean.put(cls, bean); //放入BeanFactory

        return true;
    }

}
